#include "src/base/Timestamp_v2.h"

#include "gtest/gtest.h"
#include <iostream>

using namespace sola;

TEST(TimestampTest, DefaultConstructor) {
    Timestamp ts;
    EXPECT_FALSE(ts.valid());
    EXPECT_EQ(ts.microSecondsSinceEpoch(), 0);
}

TEST(TimestampTest, FromMicroseconds) {
    int64_t   micros = 123456789;
    Timestamp ts(micros);
    EXPECT_TRUE(ts.valid());
    EXPECT_EQ(ts.microSecondsSinceEpoch(), micros);
}

TEST(TimestampTest, Now) {
    Timestamp ts1 = Timestamp::now();
    EXPECT_TRUE(ts1.valid());

    Timestamp ts2 = Timestamp::now();
    EXPECT_TRUE(ts2.valid());
    EXPECT_LE(ts1.microSecondsSinceEpoch(), ts2.microSecondsSinceEpoch());
}

TEST(TimestampTest, Conversions) {
    Timestamp now = Timestamp::now();

    // To string and formatted string
    std::string s  = now.toString();
    std::string fs = now.toFormattedString();
    std::cout << "Now (toString): " << s << std::endl;
    std::cout << "Now (toFormattedString): " << fs << std::endl;
    EXPECT_FALSE(s.empty());
    EXPECT_FALSE(fs.empty());

    // To time_point and back
    auto      tp = now.toTimePoint();
    Timestamp from_tp(tp);
    EXPECT_EQ(now, from_tp);
}

TEST(TimestampTest, Comparisons) {
    Timestamp ts1(100);
    Timestamp ts2(200);
    Timestamp ts3(100);

    EXPECT_LT(ts1, ts2);
    EXPECT_LE(ts1, ts2);
    EXPECT_GT(ts2, ts1);
    EXPECT_GE(ts2, ts1);
    EXPECT_EQ(ts1, ts3);
    EXPECT_NE(ts1, ts2);
}

TEST(TimestampTest, TimeArithmetic) {
    Timestamp start(100 * kMicroSecondsPerSecond); // 100 seconds
    double    seconds_to_add = 5.5;
    Timestamp end            = addTime(start, seconds_to_add);

    EXPECT_EQ(end.microSecondsSinceEpoch(),
              start.microSecondsSinceEpoch() + static_cast<int64_t>(seconds_to_add * kMicroSecondsPerSecond));

    double diff = timeDifference(end, start);
    EXPECT_DOUBLE_EQ(diff, seconds_to_add);

    // Chrono duration math
    Timestamp ts_plus_duration = start + std::chrono::milliseconds(1500);
    EXPECT_EQ(ts_plus_duration.microSecondsSinceEpoch(), start.microSecondsSinceEpoch() + 1500000);

    std::chrono::microseconds duration_between = end - start;
    EXPECT_EQ(duration_between.count(), static_cast<int64_t>(seconds_to_add * kMicroSecondsPerSecond));
}

TEST(TimestampTest, FromUnixTime) {
    time_t    seconds      = 1678886400; // Some specific time
    int       microseconds = 123456;
    Timestamp ts           = Timestamp::fromUnixTime(seconds, microseconds);

    EXPECT_EQ(ts.secondsSinceEpoch(), seconds);
    EXPECT_EQ(ts.microSecondsSinceEpoch(), static_cast<int64_t>(seconds) * kMicroSecondsPerSecond + microseconds);
}
